#pragma once

/**
 * This is a simple test suite C implementation. Does all the basic test suite requirements.
 * This has been intentionally written to not use any external utilities or files to simplify
 * and encourage the writing of test cases.
 *
 * Simple guide:
 * Create a TestSuite structure by calling TestSuiteCreate(). Use TestMethod as a function template
 * to implement as my tests as your heart desires using the assert methods within your test functions.
 * Finally add the test method to the TestSuite structure by calling TestSuiteAddMethod and then run
 * the test suite by calling TestSuiteRun.
 *
 * This will execute all the test methods and report the results to the standard output stream.
 *
 * Simple tip:
 * Instead of writing 10 methods to test 10 different cases for the same component, write a single
 * method and add all 10 tests with asserts and jump between them upon failure.
 *
 * @author Charbel Choueiri
 * @date 2011-01-02
 * @version 0.2
 */

/**
 * Test method template.
 */
struct TestSuite;
typedef void (*TestMethod)(struct TestSuite*);

/**
 * This is the test method structure holder. Contains the name and a single test methods
 * which is added to the test suite. Each test method may have multiple asserts, this structure
 * keeps track of total asserts and failed asserts.
 */
typedef struct UnitTest
{
	// The unique name of the test. It is up to the user to ensure the names are unique.
	char name[256];

	// Holds the total number of assert calls within this test methods and the
	// number of failed asserts. These numbers are only updated when run is called on the test suite.
	unsigned int total;
	unsigned int failed;

	// Pointers to the test method.
	TestMethod method;

	// This structure is a node within a linked list, so this points to the next unit test within the list.
	struct UnitTest* next;

}UnitTest;

/**
 * The Test Suite structure that holds all the test methods and keeps track of
 * failures for reporting.
 */
typedef struct TestSuite
{
	// These are the linked list unit tests added to this test suite.
	UnitTest* first;
	UnitTest* last;

	// When run is called this points to the currently running methods. Used by the assert to report on failures.
	UnitTest* current;

	// The total number of test methods within the test suite.
	unsigned int total;

	// Keeps track of failed test methods. A test method may have lots of failures or success
	// but this only reports 1 per method if at least one failure was reported.
	unsigned int failed;

}TestSuite;

/**
 * Creates a test suite structure and initializes all variables.
 * New test suits are empty, use TestSuiteAdd to add test methods to the test suite.
 * Any method added to the test suite must match TestMethod function declaration.
 */
TestSuite* TestSuiteCreate();

/**
 * Deletes all test methods within the test suite and frees up the structure memory.
 */
void TestSuiteDelete(TestSuite* pTestSuite);

/**
 * Deletes the unit test structure and frees the memory.
 */
void UnitTestDelete(UnitTest* pTest);

/**
 * Creates a unit test structure and returns it. This is a helper function for TestSuiteAdd.
 */
UnitTest* UnitTestCreate(char* sName, TestMethod fTestMethod);

/**
 * Adds a unit test method to the test suite. Each method must have a unique name,
 * generally the name of the method, to distinguishes it while running the tests.
 */
void TestSuiteAdd(TestSuite* pTestSuite, char* sName, TestMethod fTestMethod);

/**
 * Runs all test methods within the test suite and reports on the success or failures.
 */
void TestSuiteRun(TestSuite* pTestSuite);

/**
 * If the <result> variables is true or non-zero then the assert is successful, otherwise if it is
 * zero then the assert fails and is reported to the test suite. This is the main method of reporting
 * test method successes or failures. To assert any other type, one can write their own assert methods
 * and call this one for final reporting and pass in true or false according to the result.
 */
int Assert(TestSuite* pTestSuite, int iResult, char* sMessage);

